﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using GoogleConnector;
using Google.Documents;
using Google.GData.Client;
using DataType;
using System.Threading;
using System.IO;
using System.Reflection;
using System.IO.Pipes;
using System.Web.Mail;
using Microsoft.Win32;
using UILibrary;
using LicenseManager;
using Utilities;

namespace OfficeOnline
{
    public partial class MdiForm : Form
    {
        internal delegate void VoidDelegate();

        private Connector m_connector;
        //private LoginForm m_loginForm;
        private string m_currentDoc;
        private DocumentInfo m_docInfo;
        private DbOperations m_dbOperations;
        TraceWrapper m_traceWrapper;
        private Thread m_currentServer;
        private ThreadSafeUIOperations m_TS_UI;
        private Progress m_progressDlg;
        private Update m_updateChecker;
        private Assembly m_assembly; 

        private void setupProxy()
        {
            RegistryKey kHKCU = Registry.CurrentUser;
            RegistryKey kFirstRun;

            kFirstRun = kHKCU.OpenSubKey("Software\\UpriseApps\\OfficeInCloud", true);
            if (kFirstRun == null)
            {
                kFirstRun = kHKCU.CreateSubKey("Software\\UpriseApps\\OfficeInCloud", RegistryKeyPermissionCheck.ReadWriteSubTree);
                kFirstRun.SetValue("ProxyType", 0);
                // 0 - No Proxy
                // 1 - IE Proxy
                // 2 - Manual Proxy
            }
            if ((int)kFirstRun.GetValue("ProxyType") == 0) radioNoProxy.Checked = true;
            else
            if ((int)kFirstRun.GetValue("ProxyType") == 1) radioIEProxy.Checked = true;
            else
            if ((int)kFirstRun.GetValue("ProxyType") == 2)
            {
                radioManualProxy.Checked = true;
                maskedTextBox1.Text = (string)kFirstRun.GetValue("ProxyAddress");
                maskedTextBox2.Text = (string)kFirstRun.GetValue("ProxyPort");
                //string[] arr = ((string)kFirstRun.GetValue("ProxyAddress")).Split(new char[':']);
                //if (arr.Length > 1)
                //    maskedTextBox2.Text = arr[1];
                textBox3.Text = (string)kFirstRun.GetValue("UserName");
                textBox4.Text = (string)kFirstRun.GetValue("Password");
            }
        }

        private void loadCredentials()
        {
            Credentials cred = new Credentials(null, null);
            m_dbOperations.DoLoadCredentials(cred);

            if (cred.m_remember == true)
            {
                UserName.Text = cred.m_Cred.Username;
                Password.Text = cred.m_password;
                checkRemember.Checked = cred.m_remember;
            }
        }

        private void provideDisabledMode()
        {
            UserName.Enabled = false;
            Password.Enabled = false;
            checkRemember.Enabled = false;
            LoginButton.Enabled = false;
            RegistrationLink.Visible = true;
        }

        private void setImages()
        {
            ImageList imageList = new ImageList();
            imageList.ColorDepth = ColorDepth.Depth32Bit;
            imageList.TransparentColor = Color.Transparent;
            imageList.ImageSize = new Size(20, 20);

            imageList.Images.Add(Properties.Resources.UpriseApps);
            imageList.Images.Add(Properties.Resources.Folder);
            imageList.Images.Add(Properties.Resources.Pastel_Icons_settings_ico_32x32);

            MyGDocsTabControl.ImageList = imageList;
            MyGDocsTabControl.TabPages["SignIn"].ImageIndex = 0;
            MyGDocsTabControl.TabPages["SupportTab"].ImageIndex = 1;
            MyGDocsTabControl.TabPages["tabProxy"].ImageIndex = 2;
        }


        public MdiForm(string doc, DbOperations _db, TraceWrapper traceWrapper, bool disabled, Assembly assembly)
        {
            InitializeComponent();

            m_assembly = assembly; 

            m_updateChecker = new Update();

            m_dbOperations = _db;
            m_traceWrapper = traceWrapper;
            m_progressDlg = new Progress();
            m_TS_UI = new ThreadSafeUIOperations();
            m_connector = new Connector();
            
            m_currentDoc = doc;
            this.IsMdiContainer = true;

            RegistrationLink.Visible = false;
            FeedbackBtn.Enabled = false;
            SupportMsg.Text = Properties.Resources.SupportTemplate;

            setImages();

            setupProxy();

            loadCredentials();

            if (UserName.Text.Trim() != "" && Password.Text.Trim() != "")
                LoginButton_Click(this, null); 

            if (disabled)
                provideDisabledMode();

            m_webBrowser.NewWindow += new CancelEventHandler(m_webBrowser_NewWindow);
        }

        private void openDocument(string document)
        {
            string fname = System.IO.Path.GetFileNameWithoutExtension(document);
            m_docInfo = new DocumentInfo(document, fname);
            m_connector.UploadDocument(null, m_docInfo);

            //MdiChild frmchild = new MdiChild();
            //frmchild.MdiParent = this;
            //frmchild.Text = fname;
            m_TS_UI.SetVisible(m_webBrowser, true);
            m_TS_UI.SetUrl(m_webBrowser, m_docInfo.m_DocEntry.AlternateUri.ToString());

            //m_webBrowser.Visible = true;
            //m_webBrowser.Url = new Uri(m_docInfo.m_DocEntry.AlternateUri.ToString());
            //m_webBrowser.AllowNavigation = true;
        }

        void m_webBrowser_NewWindow(object sender, CancelEventArgs e)
        {
            e.Cancel = true; //Stop event from being processed

            ////Code to open in same window
            this.m_webBrowser.Navigate(m_docInfo.m_DocEntry.AlternateUri.ToString());
        }

        public void login()
        {   this.Show();}

        private Document.DownloadType provideType(string extension)
        {
            Document.DownloadType type;
            switch(extension)
            {
                case ".docx": 
                case ".doc": return Document.DownloadType.doc;
                
                case ".xlsx": 
                case ".xls": return Document.DownloadType.xls;

                case ".ppt": return Document.DownloadType.ppt;
                
                default: throw new System.Exception("This extension is not supported " + extension);
            }
        }

        //the service doesn't allow to download .xlsx/docx, if original document is one of it
        //it's necessary to use .xls/doc for download
        private string provideExt(string extension)
        {
            Document.DownloadType type;
            switch (extension)
            {
                case ".docx": return ".doc";
                case ".xlsx": return ".xls";
                
                default: return extension;
            }
        }

        private string downloadImpl()
        {
            Document.DownloadType type;
            FileInfo fileInfo = null;
            FileStream stream = null;
            string tmp_doc_name;

            try
            {
            //Document.DownloadType type = Document.DownloadType.doc;
            type = provideType(System.IO.Path.GetExtension(m_currentDoc));
            Document dt = new Document();
            dt.AtomEntry = m_docInfo.m_DocEntry;
            DownloadInfo info = new DownloadInfo(dt, type);

            m_connector.DownloadDocument(null, info);
            string file_name = System.IO.Path.GetFileNameWithoutExtension(m_currentDoc);
            string file_ext = provideExt(System.IO.Path.GetExtension(m_currentDoc));
            string file_path = System.IO.Path.GetDirectoryName(m_currentDoc);
            tmp_doc_name = file_path + "\\" + file_name + "_tmp" + file_ext;
            fileInfo = new FileInfo(tmp_doc_name);
            stream = null;
         
                stream = fileInfo.Open(FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
                Utilities.CommonOperations.DoSaveContent(stream, info.m_Stream);
                stream.Close();
            }
            catch (System.Exception ex)
            {
                if (stream!=null) stream.Close();
                if (fileInfo!=null) fileInfo.Delete();

                throw ex;
            }

            return tmp_doc_name;
        }

        private void replaceOriginal(string tmpPath)
        {
            FileInfo fiTmp = null;
            try
            {
                FileInfo fiOrig = new FileInfo(m_currentDoc);
                fiOrig.Delete();

                fiTmp = new FileInfo(tmpPath);
                //if document was xlsx/docx we replace it as xls/doc since there is no conversion from
                //downloaded type xls/doc to the xlsx/docx
                string resultPath = tmpPath.Replace("_tmp", "");
                m_currentDoc = resultPath;
                fiTmp.MoveTo(m_currentDoc);
            }
            catch (System.Exception ex)
            {
                fiTmp.Delete();
                //if error happens leave version at cloud
                throw ex;
            }
        }

        private void DoDownloadDocument()
        {
            try
            {
                //download to the tmp file, if no error happens then replace the original file
                string tmp_doc_name = downloadImpl();
                replaceOriginal(tmp_doc_name);
            }
            catch (Exception e)
            {

            }
            finally
            {
                if (m_progressDlg.InvokeRequired)
                {
                    VoidDelegate dlg = new VoidDelegate(CloseProgressDlgAfterLogin);
                    m_progressDlg.Invoke(dlg);
                }
                else m_progressDlg.Close();
            }
        }

        private void saveBtn_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void docOperations()
        {
            try
            {
                ThreadStart newThreadStart = new ThreadStart(DoDownloadDocument);
                Thread newThread = new Thread(newThreadStart);

                newThread.Start();
                m_progressDlg.ShowDialog(this);

                ((Google.GData.Client.GDataRequestFactory)m_connector.m_Service.RequestFactory).CustomHeaders.Add(Google.GData.Client.GDataRequestFactory.IfMatch + ":*");
                ((Google.GData.Client.GDataRequestFactory)m_connector.m_Service.RequestFactory).CustomHeaders.Add(Google.GData.Client.GDataRequestFactory.IfNoneMatch + ":" + Guid.NewGuid().ToString());
                m_docInfo.m_DocEntry.Delete();
            }
            catch (System.Exception ex)
            {
            }
        }

        private void MdiForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (m_docInfo == null)
                return;

            //download and remove remote copy
            docOperations();
        }

        private void CloseProgressDlgAfterLogin()
        {
            m_progressDlg.Close();

            //check for updates only after all operation in thread was finished
            m_updateChecker.checkForUpdates(Properties.Resources.AppUpdateName, 
                                            System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString());
        }

        private void CloseProgressDlg()
        {
            m_progressDlg.Close();
        }

        //progress window code
        private void DoAllLogins()
        {
            try
            {
                LicenseManager.ZohoLicenseManager lm = new ZohoLicenseManager("info@upriseapps.com", "mamamilaramu", m_dbOperations, m_assembly);
                lm.Login();
                lm.LoadRegisteredUser();
                lm.RegisteredContactUpdate();
                if (lm.RegisteredContactBlocked())
                    throw new ZohoLicenseBlocked();
                if (lm.RegisteredLicenseExpired())
                    throw new ZohoLicenseExpired();

                Credentials cred = new Credentials(UserName.Text, Password.Text);
                m_connector.Login(null, cred);
                openDocument(m_currentDoc);
                //processLogin(UserName.Text, Password.Text);

                if (checkRemember.Checked)
                    cred.m_remember = true;
                else
                    cred.m_remember = false;

                m_dbOperations.DoSaveCredentials(cred);

                m_TS_UI.SetForeColor(StatusMessage, Color.Black);
                m_TS_UI.SetText(StatusMessage, Properties.Resources.LoginSucceeded);

                m_TS_UI.SetEnabled(FeedbackBtn, true);
                //m_TS_UI.SetEnabled(SignIn, false);
                m_TS_UI.SetEnabled(LoginButton, false);
                m_TS_UI.SetEnabled(UserName, false);
                m_TS_UI.SetEnabled(Password, false);
                m_TS_UI.SetEnabled(checkRemember, false);
                m_TS_UI.SetEnabled(signOut, true);
            }
            catch (AuthenticationException ex)
            {
                Utilities.TraceWrapper.LogException("Login_Click error: " + ex.Message, ex);

                m_TS_UI.SetEnabled(FeedbackBtn, false);
                m_TS_UI.SetForeColor(StatusMessage, Color.Red);
                m_TS_UI.SetText(StatusMessage, Properties.Resources.ErrorPrefix + ex.Message);
            }
            catch (ZohoLicenseBlocked ex)
            {
                TraceWrapper.LogException("Login_Click error: " + ex.Message, ex);

                MessageBox.Show("We'd like to inform you that your Office In Cloud license is blocked. \n" +
                                 "Please contact Uprise Apps support: info@upriseapps.com for details.");
            }
            catch (ZohoLicenseExpired ex)
            {
                TraceWrapper.LogException("Login_Click error: " + ex.Message, ex);

                LicenseExpired dialog = new LicenseExpired();
                dialog.ShowDialog();
            }
            catch (ZohoUserDataException ex)
            {
                //First Run
                RegistryKey kHKCU = Registry.CurrentUser;
                RegistryKey kFirstRun;

                kFirstRun = kHKCU.OpenSubKey("Software\\UpriseApps\\OfficeOnline", true);
                kFirstRun = kHKCU.CreateSubKey("Software\\UpriseApps\\OfficeOnline", RegistryKeyPermissionCheck.ReadWriteSubTree);
                kFirstRun.SetValue("FirstRun", 1);
                MessageBox.Show("Your user data was not registered. \n Please restart the application in order to pass registration.", "Office In Cloud Error Message");
            }
            catch (Exception ex)
            {
                TraceWrapper.LogException("Login_Click error: " + ex.Message, ex);

                m_TS_UI.SetEnabled(FeedbackBtn, false);
                m_TS_UI.SetForeColor(StatusMessage, Color.Red);
                m_TS_UI.SetText(StatusMessage, Properties.Resources.ErrorPrefix + ex.Message);
            }
            finally
            {
                m_TS_UI.SetVisible(StatusMessage, true);

                if (m_progressDlg.InvokeRequired)
                {
                    VoidDelegate dlg = new VoidDelegate(CloseProgressDlgAfterLogin);
                    m_progressDlg.Invoke(dlg);
                }
                else m_progressDlg.Close();
            }
        }

        private void LoginButton_Click(object sender, EventArgs e)
        {
            m_TS_UI.SetVisible(StatusMessage, false);
            m_TS_UI.SetEnabled(LoginButton, false);
            m_TS_UI.SetEnabled(signOut, false);
            //LoginProgress.Visible = true;
            m_TS_UI.SetEnabled(UserName, false);
            m_TS_UI.SetEnabled(Password, false);
            m_TS_UI.SetEnabled(checkRemember, false);

            ThreadStart newThreadStart = new ThreadStart(DoAllLogins);
            Thread newThread = new Thread(newThreadStart);

            newThread.Start();
            m_progressDlg.ShowDialog(this);
        }

        private void RegistrationLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Registration regForm = new Registration(m_dbOperations, m_assembly);
            if (regForm.ShowDialog() == DialogResult.OK)
            {
                RegistryKey kHKCU = Registry.CurrentUser;
                RegistryKey kFirstRun = kHKCU.OpenSubKey("Software\\UpriseApps\\OfficeOnline", true);
                kFirstRun.SetValue("FirstRun", 0);

                UserName.Enabled = true;
                Password.Enabled = true;
                checkRemember.Enabled = true;
                LoginButton.Enabled = true;
                RegistrationLink.Visible = false;
            }
        }

        private void PrepareSendMessage(MailMessage mail)
        {
            //Ensure priority is set to "NORMAL
            mail.Priority = MailPriority.Normal;
            //  Use Authentication
            mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
            //Use this Username to Authenticate
            mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", this.UserName.Text);
            //Use this Password to Authenticate
            mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", this.Password.Text);
            //Use STARTTLS (some clients call this SSL) - Gmail help page indicated it used this
            mail.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", "true");
            // assign outgoing gmail server
            SmtpMail.SmtpServer = "smtp.gmail.com";
            SmtpMail.Send(mail);
        }

        private void FeedbackBtn_Click(object sender, EventArgs e)
        {
            try
            {
                MailMessage mail = new MailMessage();

                mail.To = "support@upriseapps.com";

                if (!this.UserName.Text.Contains("@"))
                    mail.From = this.UserName.Text + "@gmail.com";
                else
                    mail.From = this.UserName.Text;

                if (SupportSubj.Text.Trim().Length == 0)
                    mail.Subject = Properties.Resources.FeedbackSubject;
                else
                    mail.Subject = SupportSubj.Text;

                mail.Body = Properties.Resources.MsgFeedbackPrefix;

                if (SupportMsg.Text.Trim().Length != 0)
                {
                    mail.Body += "\n";
                    mail.Body += SupportMsg.Text;
                }

                mail.Body += "\n";
                mail.Body += "With best wishes From Uprise Apps Office In Cloud.";

                m_traceWrapper.shutdownTraceListener();
                mail.Attachments.Add(new MailAttachment(Utilities.Path.logPath));

                PrepareSendMessage(mail);
            }
            catch (System.Exception ex)
            {
                m_traceWrapper.initTraceListener();
                Utilities.TraceWrapper.LogException("SendBtn_Click error: " + ex.Message, ex);
            }
        }

        private void btnApply_Click(object sender, EventArgs e)
        {
            // Save proxy settings to registry. 
            RegistryKey kHKCU = Registry.CurrentUser;
            RegistryKey kFirstRun;

            kFirstRun = kHKCU.OpenSubKey("Software\\UpriseApps\\OfficeInCloud", true);
            if (kFirstRun == null)
            {
                kFirstRun = kHKCU.CreateSubKey("Software\\UpriseApps\\OfficeInCloud", RegistryKeyPermissionCheck.ReadWriteSubTree);
                kFirstRun.SetValue("ProxyType", 0);
                // 0 - No Proxy
                // 1 - IE Proxy
                // 2 - Manual Proxy
            }
            if (radioNoProxy.Checked)
                kFirstRun.SetValue("ProxyType", 0);
            else if (radioIEProxy.Checked)
                kFirstRun.SetValue("ProxyType", 1);
            else if (radioManualProxy.Checked)
            {
                string address = maskedTextBox1.Text;
                string port = maskedTextBox2.Text;

                //if (port.Trim().Length > 0) address = address + ":" + port; 
                kFirstRun.SetValue("ProxyType", 2);
                kFirstRun.SetValue("ProxyAddress", address);
                kFirstRun.SetValue("ProxyPort", port);
                kFirstRun.SetValue("UserName", textBox3.Text);
                kFirstRun.SetValue("Password", textBox4.Text);
            }
        }

        private void cleanUpLoadedContext()
        {
            ((Google.GData.Client.GDataRequestFactory)m_connector.m_Service.RequestFactory).CustomHeaders.Add(Google.GData.Client.GDataRequestFactory.IfMatch + ":*");
            ((Google.GData.Client.GDataRequestFactory)m_connector.m_Service.RequestFactory).CustomHeaders.Add(Google.GData.Client.GDataRequestFactory.IfNoneMatch + ":" + Guid.NewGuid().ToString());
            m_docInfo.m_DocEntry.Delete();
        }

        private void signOut_Click(object sender, EventArgs e)
        {
            if (m_docInfo != null)
                cleanUpLoadedContext();

            UserName.Text = "";
            Password.Text = "";
            LoginButton.Enabled = true;
            checkRemember.Enabled = true;
            UserName.Enabled = true;
            Password.Enabled = true;

            m_webBrowser.Navigate("http://docs.google.com/logout");
        }

        private void saveAsBtn_Click(object sender, EventArgs e)
        {
            SaveFileDialog expDialog = new SaveFileDialog();
            expDialog.InitialDirectory = Utilities.Path.documentPath;
            Document.DownloadType type = provideType(System.IO.Path.GetExtension(m_currentDoc));
            string filter = string.Empty;
            switch(type)
            {
                case Document.DownloadType.doc: filter = "Word|*.doc";break;
                case Document.DownloadType.xls: filter = "Excel|*.xls"; break;
                case Document.DownloadType.ppt: filter = "PowerPoint|*.ppt"; break;
                default: filter = "*.*"; break;
            }

            expDialog.Filter = filter;

            string fileName = string.Empty;

            if (System.IO.Path.HasExtension(fileName))
                fileName = System.IO.Path.GetFileNameWithoutExtension(fileName);
            
            expDialog.FileName = fileName;

            if (expDialog.ShowDialog() == DialogResult.OK)
            {
                m_currentDoc = expDialog.FileName;
                this.Close();
            }
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            m_updateChecker.checkForUpdates(Properties.Resources.AppUpdateName, 
                                            System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString());
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox(System.Reflection.Assembly.GetEntryAssembly());
            about.ShowDialog(); 
        }

        private void splitContainer1_Panel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void splitContainer1_Panel2_ClientSizeChanged(object sender, EventArgs e)
        {
            SplitterPanel pn = sender as SplitterPanel;
            this.MyGDocsTabControl.Size = pn.Size;
        }
    }
}
